﻿'Copyright (c) 2009 Grailtek

'Permission is hereby granted, free of charge, to any person
'obtaining a copy of this software and associated documentation
'files (the "Software"), to deal in the Software without
'restriction, including without limitation the rights to use,
'copy, modify, merge, publish, distribute, sublicense, and/or sell
'copies of the Software, and to permit persons to whom the
'Software is furnished to do so, subject to the following
'conditions:

'The above copyright notice and this permission notice shall be
'included in all copies or substantial portions of the Software.

'THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
'EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
'OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
'NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
'HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
'WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
'FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
'OTHER DEALINGS IN THE SOFTWARE.

Imports System.Aspect

Public Class ArgumentsEntry
    Inherits Panel

    Private _Arguments() As Argument
    Public Property Arguments() As Argument()
        Get
            Return _Arguments
        End Get
        Set(ByVal value As Argument())
            _Arguments = value
            OnArgumentsChanged()
        End Set
    End Property

    Private Class ArgumentEntry
        Inherits Panel
        Public Sub New()
            Me.Controls.Add(Label)
            Label.Dock = DockStyle.Left
            Label.TextAlign = ContentAlignment.MiddleLeft
            Label.AutoSize = True
            Me.Controls.Add(TextBox)
            TextBox.Dock = DockStyle.Fill
            TextBox.BringToFront()
        End Sub
        Private ReadOnly Label As New Label
        Private WithEvents TextBox As New TextBox
        Private ReadOnly tt As New ToolTip
        Private WithEvents _Arg As Argument
        Public Property Arg() As Argument
            Get
                Return _Arg
            End Get
            Set(ByVal value As Argument)
                _Arg = value
                UpdateArgText()
            End Set
        End Property
        Private Sub UpdateArgText()
            Dim paramName As String = Nothing
            _ArgType = Nothing
            _ArgTypeIsConvertible = False
            If Not _Arg Is Nothing Then
                paramName = _Arg.ParamUIName
                _ArgType = _Arg.Param.ParameterType
                _ArgTypeIsConvertible = GetType(IConvertible).IsAssignableFrom(_ArgType)
            End If
            Label.Text = paramName
            Dim txt As String = Nothing
            TextBox.Enabled = _ArgTypeIsConvertible
            If _ArgTypeIsConvertible Then
                txt = CStr(_Arg.Value)
            Else
                If Not Arg.Value Is Nothing Then txt = String.Format("({0})", Arg.Param.ParameterType.Name)
            End If
            TextBox.Text = txt
        End Sub
        Private _ArgType As Type
        Private _ArgTypeIsConvertible As Boolean
        Private Sub TextBox_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox.TextChanged
            Dim txt As String = TextBox.Text
            If _ArgTypeIsConvertible Then
                If String.IsNullOrEmpty(txt) Then
                    If EntryError Then ClearError() 'TODO: how far will we go with this? param required versus not required?
                Else
                    Try
                        _ignoreArgChange = True
                        _Arg.Value = Convert.ChangeType(txt, _ArgType)
                        If EntryError Then ClearError()
                    Catch ex As FormatException
                        SetError(ex.Message)
                    Finally
                        _ignoreArgChange = False
                    End Try
                End If
            End If
        End Sub
        Private Sub SetError(ByVal msg As String)
            _EntryError = True
            TextBox.ForeColor = Color.Red
            _Arg.Value = Nothing
            tt.SetToolTip(TextBox, msg)
        End Sub
        Private Sub ClearError()
            _EntryError = False
            TextBox.ForeColor = Color.Black
            tt.RemoveAll()
        End Sub
        Private _EntryError As Boolean
        Public ReadOnly Property EntryError() As Boolean
            Get
                Return _EntryError
            End Get
        End Property
        Private _ignoreArgChange As Boolean = False
        Private Sub _Arg_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles _Arg.ValueChanged
            If _ignoreArgChange Then Return
            UpdateArgText()
        End Sub
    End Class

    Private Entries As New List(Of ArgumentEntry)

    Protected Overridable Sub OnArgumentsChanged()
        For Each e As ArgumentEntry In Entries
            e.Visible = False
        Next
        If Arguments Is Nothing OrElse Arguments.Count = 0 Then Return
        Dim NeededNewFields As Integer = Arguments.Count - Entries.Count
        If NeededNewFields > 0 Then
            For i As Integer = 1 To NeededNewFields
                Dim e As New ArgumentEntry
                Entries.Add(e)
                Me.Controls.Add(e)
                e.BringToFront()
            Next
        End If
        For i As Integer = 0 To Arguments.GetUpperBound(0)
            Dim e As ArgumentEntry = Entries(i)
            Entries(i).Arg = Arguments(i)
            e.Visible = True
        Next
    End Sub

End Class
